package com.eian.boot.module.system.associations.user.role.service;

import com.eian.boot.module.system.associations.user.role.event.RoleUnassignedEvent;
import com.eian.boot.module.system.associations.user.role.event.UserRoleAssignedEvent;
import com.eian.boot.module.system.associations.user.role.event.UserRoleRemovedEvent;
import com.eian.boot.module.system.associations.user.role.mapper.UserRoleMapper;
import com.eian.boot.module.system.associations.user.role.model.entity.SysUserRoleEntity;
import com.eian.boot.mybatis.core.service.BaseService;
import com.mybatisflex.core.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

import static com.eian.boot.table.Tables.sys_user_role;

/**
 * 用户角色关系管理服务
 * 职责：纯粹的关系数据管理，不包含业务逻辑验证
 *
 * @author alex.meng
 * @since 1.0.0
 */
@Slf4j
@Service
public class UserRoleRelationService extends BaseService<UserRoleMapper, SysUserRoleEntity> {

    private final ApplicationEventPublisher eventPublisher;

    public UserRoleRelationService(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }

    /**
     * 分配用户角色（唯一写入口）
     * 先清除旧关系，再建立新关系
     *
     * @param userId  用户ID
     * @param roleIds 角色ID列表
     */
    @Transactional(rollbackFor = Exception.class)
    public void assignUserRoles(Long userId, List<Long> roleIds) {
        log.debug("分配用户角色: userId={}, roleIds={}", userId, roleIds);

        // 清除旧关系
        this.remove(QueryWrapper.create()
                .from(sys_user_role)
                .where(sys_user_role.user_id.eq(userId)));

        // 建立新关系
        if (roleIds != null && !roleIds.isEmpty()) {
            List<SysUserRoleEntity> relations = roleIds.stream()
                    .map(roleId -> SysUserRoleEntity.builder()
                            .userId(userId)
                            .roleId(roleId)
                            .build())
                    .collect(Collectors.toList());
            this.saveBatch(relations);
        }

        // 发布领域事件
        eventPublisher.publishEvent(new UserRoleAssignedEvent(this, userId, roleIds));
    }

    /**
     * 查询用户的角色ID列表
     *
     * @param userId 用户ID
     * @return 角色ID列表
     */
    public List<Long> getRoleIdsByUserId(Long userId) {
        return this.queryChain()
                .select(sys_user_role.role_id)
                .from(sys_user_role)
                .where(sys_user_role.user_id.eq(userId))
                .listAs(Long.class);
    }

    /**
     * 查询角色下的用户ID列表
     *
     * @param roleId 角色ID
     * @return 用户ID列表
     */
    public List<Long> getUserIdsByRoleId(Long roleId) {
        return this.queryChain()
                .select(sys_user_role.user_id)
                .from(sys_user_role)
                .where(sys_user_role.role_id.eq(roleId))
                .listAs(Long.class);
    }

    /**
     * 检查角色是否有用户绑定
     *
     * @param roleId 角色ID
     * @return true-有绑定，false-无绑定
     */
    public boolean checkRoleHasUsers(Long roleId) {
        return this.queryChain()
                .from(sys_user_role)
                .where(sys_user_role.role_id.eq(roleId))
                .exists();
    }

    /**
     * 级联删除：当用户被删除时调用
     * 清理用户的所有角色关系
     *
     * @param userId 用户ID
     */
    @Transactional(rollbackFor = Exception.class)
    public void cascadeDeleteByUserId(Long userId) {
        log.debug("级联删除用户角色关系: userId={}", userId);

        // 先查询要删除的角色ID（用于事件通知）
        List<Long> roleIds = this.getRoleIdsByUserId(userId);

        // 删除关系
        this.remove(QueryWrapper.create()
                .from(sys_user_role)
                .where(sys_user_role.user_id.eq(userId)));

        // 发布事件
        if (!roleIds.isEmpty()) {
            eventPublisher.publishEvent(new UserRoleRemovedEvent(this, userId, roleIds));
        }
    }

    /**
     * 级联删除：当角色被删除时调用
     * 清理角色与所有用户的关系
     *
     * @param roleId 角色ID
     */
    @Transactional(rollbackFor = Exception.class)
    public void cascadeDeleteByRoleId(Long roleId) {
        log.debug("级联删除角色用户关系: roleId={}", roleId);

        // 先查询要删除的用户ID（用于事件通知）
        List<Long> userIds = this.getUserIdsByRoleId(roleId);

        // 删除关系
        this.remove(QueryWrapper.create()
                .from(sys_user_role)
                .where(sys_user_role.role_id.eq(roleId)));

        // 发布事件
        if (!userIds.isEmpty()) {
            eventPublisher.publishEvent(new RoleUnassignedEvent(this, roleId, userIds));
        }
    }
}

